// Copyright 2010 Google Inc.
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//      http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <assert.h>

#include "engine/globals.h"
#include "public/commandlineflags.h"
#include "public/logging.h"

#include "utilities/quotefmt.h"

#include "engine/memory.h"
#include "engine/utils.h"
#include "engine/opcode.h"
#include "engine/map.h"
#include "engine/scope.h"
#include "engine/type.h"
#include "engine/node.h"
#include "engine/symboltable.h"
#include "engine/scanner.h"
#include "engine/frame.h"
#include "engine/printvisitor.h"
#include "engine/proc.h"
#include "engine/taggedptrs.h"
#include "engine/form.h"
#include "engine/val.h"
#include "engine/factory.h"
#include "engine/engine.h"


DEFINE_bool(trace_code, false, "trace executed instructions");
DEFINE_bool(trace_traps, false, "trace trap resolution (debugging)");
DEFINE_bool(debug_whens, false, "print when statements before and after rewriting");
DEFINE_int32(heap_chunk_size, 10240, "heap chunk size in KB");
DEFINE_int32(stack_size, 256, "stack size in KB");
DEFINE_int32(stacktrace_length, 20, "maximum stacktrace length");

DEFINE_bool(restrict, false, "enable security restrictions. Programs will not "
                             "be allowed to use the 'proc' and 'file' "
                             "modifiers.");
DEFINE_bool(ignore_multiple_inclusion, true,
            "disregard second and subsequent "
            "invocation of include or proto file");
DEFINE_bool(show_multiple_inclusion_warnings, false,
            "show warnings generated by --ignore_multiple_inclusion "
            "when a file is included multiple times");

DEFINE_bool(preallocate_default_proto, true, "allocate default values for proto buffer TupleTypes");

// Debugging
DEFINE_bool(trace_refs, false, "trace reference counts (debugging)");  // used in dbg only


namespace sawzall {

// Complete list of C99 formats and (letter) modifiers:
//   A   EFG    L            X    a cdefghij l nop  stu  x z
// Predefined Fmt formats and (letter) modifiers:
//     C EFG    L      S     X     bcdefghi  l nop rs u  x

// Formats:
//  %A  parenthesized list of arguments
//  %I  full instruction as a Instr**
//  %k  single-quoted char; %#k makes hex for non-ascii
//  %H  source line info (header traceback); takes Scanner* argument
//  %L  file and line info; takes FileLine* argument
//  %N  general Node from PrintVisitor
//  %n  general Node from raw source
//  %O  Scope
//  %P  parenthesized Node
//  %Q  double-quoted Rune strings; %#Q makes hex for non-ascii
//  %q  double-quoted UTF-8 strings; %#q makes hex for non-ascii
//  %T  Type; #T causes full definition
//  %t  print N tabs; N is argument
//  %V  Val; takes 2 args: Proc* and Val*
//  %Y  Symbol (Scanner token)
//  %z  %q but handles embedded \0
//  %Z  %Q but handles embedded \0

Fmt::Formatter F;

void InstallFmts() {
  F.installverb('A', true, PrintNodeVisitor::ArgSzlListFmt);
  F.installverb('H', true, Scanner::SzlSourceLineFmt);
  F.installverb('I', true, InstrFmt);
  F.installverb('k', true, SQRuneFmt);
  F.installverb('L', true, Scanner::SzlFileLineFmt);
  F.installverb('N', true, PrintNodeVisitor::NodeFmt);
  F.installverb('n', true, Node::NodeFmt);
  F.installverb('P', true, PrintNodeVisitor::NodeFmt);
  F.installverb('Q', true, DQRuneStrFmt);
  F.installverb('q', true, DQUTF8StrFmt);
  F.installverb('T', true, PrintTypeVisitor::TypeFmt);
  F.installverb('t', true, PrintNodeVisitor::TabFmt);
  F.installverb('V', true, Val::ValFmt);
  F.installverb('Y', true, Scanner::SymbolFmt);
  F.installverb('z', true, ZDQUTF8StrFmt);
  F.installverb('Z', true, ZDQRuneStrFmt);
}


void FatalError(const char *fmt, ...) {
  Fmt::State f;
  char buf[128];
  va_list arg;

  F.fmtfdinit(&f, 2, buf, sizeof buf);
  F.fmtprint(&f, "szl: fatal: ");
  va_start(arg, fmt);
  F.fmtvprint(&f, fmt, &arg);
  va_end(arg);
  F.fmtprint(&f, "\n");
  F.fmtfdflush(&f);
  exit(1);
}


void* Allocate(Proc* proc, size_t size) {
  // Only allowed at compile time, e.g. List<> and Stack<>.
  assert((proc->mode() & Proc::kPersistent) != 0);
  return ALLOC(proc, void*, size);
}


void Deallocate(Proc* proc, void* p) {
  FREE(proc, p);
}


// String generated when formatting a bad time value.
extern const char kStringForInvalidTime[] = "[invalid time value]";

}  // namespace sawzall
